package gui;

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;

import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

import neuronska.BackPropagation;
import util.ImageUtil;
import util.KMeans1;
import util.RasterRegion;

import com.sun.xml.internal.ws.util.StringUtils;

@SuppressWarnings("serial")
public class VerticalToolbar extends JPanel {

	JButton bt1;
	JTextArea jtxt1;
	JTextArea jtxt2;
	JButton bt2;
	JButton bt3;
	JButton bt4;
	public static ArrayList<RasterRegion> kandidati;
	public double[][][] obucavajuciSkup = null;
    public int brojUzoraka = 0;
    public BackPropagation bp = null;
    HashMap<String, Integer> alfabet = new HashMap<String, Integer>();
    HashMap<Integer, String> alfabetInv = new HashMap<Integer, String>();
    String newLine = System.getProperty("line.separator");
    HashSet<String> recnik = null;
    int maxX = 0;
    int maxY = 0;
    int minY = 0;
    
    private ArrayList<RasterRegion> SpojiTackeIKukice(ArrayList<RasterRegion> regions)
    {
        // spojiti regione na takav nacin da 
        // tacke iznad slova (npr. u  i,j)
        // i kukice iznad slova (npr. u š,č,ć,ž)
        // ne budu zasebni regioni, već da pripadaju celom slovu
    	ArrayList<RasterRegion> reg = new ArrayList<RasterRegion>();
    	boolean b = false;
    	do {
    	b = false;	
        for (int i = 0; i < regions.size() - 1; i++)
            for (int j = i + 1; j < regions.size(); j++)
            {
       //     	int diffx = Math.abs(regions.get(j).maxX - regions.get(j).minX);
                int diffy = Math.abs(regions.get(j).maxY - regions.get(j).minY);
                if ((regions.get(i).xM <= regions.get(j).maxX+2  && regions.get(i).xM >= regions.get(j).minX-2
                    && ((Math.abs(regions.get(j).minY - regions.get(i).maxY) < 5*diffy / 11|| Math.abs(regions.get(i).minY - regions.get(j).maxY) <6*diffy / 11)
                    || (Math.abs(regions.get(j).minY - regions.get(i).maxY) < 4 || Math.abs(regions.get(i).minY - regions.get(j).maxY) < 4)))
                    || ((Math.abs(regions.get(j).minX - regions.get(i).maxX) < 2 || Math.abs(regions.get(i).minX - regions.get(j).maxX) < 2)
                      && (Math.abs(regions.get(j).minY - regions.get(i).maxY) < 6|| Math.abs(regions.get(i).minY - regions.get(j).maxY) < 6))
                     || (regions.get(i).xM ==regions.get(j).xM
                      && (Math.abs(regions.get(j).minY - regions.get(i).maxY) < 9 || Math.abs(regions.get(i).minY - regions.get(j).maxY) < 9))
                    || (Math.abs(regions.get(i).xM - regions.get(j).xM) <= 2 && diffy != 0 && (double)Math.abs(regions.get(i).maxY - regions.get(i).minY) / (double)diffy <= 0.5 
                      && (Math.abs(regions.get(j).minY - regions.get(i).maxY) < 12 || Math.abs(regions.get(i).minY - regions.get(j).maxY) < 12))
                     || (((regions.get(i).xM <= regions.get(j).maxX && regions.get(i).xM >= regions.get(j).minX) && (regions.get(i).yM <= regions.get(j).maxY && regions.get(i).yM >= regions.get(j).minY))
                      || ((regions.get(j).xM <= regions.get(i).maxX && regions.get(j).xM >= regions.get(i).minX) && (regions.get(j).yM <= regions.get(i).maxY && regions.get(j).yM >= regions.get(i).minY))))
                {
                    regions.get(j).points.addAll(regions.get(i).points);
                    //  regions.Remove(regions[i]);
                    b = true;
                    reg.add(regions.get(i));
                }

            }
        for (RasterRegion r : reg)
        {
            if (regions.contains(r))
                regions.remove(r);
        }
        
        reg.clear();
        
        for (RasterRegion r : regions)
          r.odrediMomente();
        
    } while (b);
    	
        return regions;
    }
	
	public void equalizeRegions(ArrayList<RasterRegion>	regions) {
		  if (regions.size() <= 1) return;

           maxX = regions.get(0).maxX - regions.get(0).minX;
           maxY = regions.get(0).maxY;
           minY = regions.get(0).minY;

          for (int i = 1; i < regions.size(); i++)
          {
              maxX = (regions.get(i).maxX - regions.get(i).minX > maxX) ? regions.get(i).maxX - regions.get(i).minX : maxX;
              maxY = (regions.get(i).maxY > maxY) ? regions.get(i).maxY : maxY;
              minY = (regions.get(i).minY < minY) ? regions.get(i).minY : minY;
          }
          for (int i = 0; i < regions.size(); i++)
          {
              regions.get(i).maxX = regions.get(i).minX + maxX;
           // regions.get(i).maxY = maxY;
           // regions.get(i).minY = minY;
            regions.get(i).maxY = regions.get(i).minY + maxY - minY;
            regions.get(i).points.add(new Point2D.Double(regions.get(i).minX, regions.get(i).minY));
            regions.get(i).points.add(new Point2D.Double(regions.get(i).minX, regions.get(i).maxY));
            regions.get(i).points.add(new Point2D.Double(regions.get(i).maxX, regions.get(i).maxY));
            regions.get(i).points.add(new Point2D.Double(regions.get(i).maxX, regions.get(i).minY));
          }
	}
	
	public void equalizeRegions1(ArrayList<RasterRegion>	regions) {
		  if (regions.size() <= 1) return;

     
        for (int i = 0; i < regions.size(); i++)
        {
            regions.get(i).maxX = regions.get(i).minX + maxX;
         // regions.get(i).maxY = maxY;
         // regions.get(i).minY = minY;
          regions.get(i).maxY = regions.get(i).minY + maxY - minY;
          regions.get(i).points.add(new Point2D.Double(regions.get(i).minX, regions.get(i).minY));
          regions.get(i).points.add(new Point2D.Double(regions.get(i).minX, regions.get(i).maxY));
          regions.get(i).points.add(new Point2D.Double(regions.get(i).maxX, regions.get(i).maxY));
          regions.get(i).points.add(new Point2D.Double(regions.get(i).maxX, regions.get(i).minY));
        }
	}
	
    private double[] pripremiSlikuZaVNM(short[][] slika)
    {
        // na osnovu slike koja je dimenzija 64x64 napraviti vektor od 64 elementa
        double[] retVal = new double[64];

        for (int i = 0; i < slika.length; i++)
        {
            for (int j = 0; j < slika[0].length; j++)
            {
                if (slika[i][j] < 255)
                {
                    int ii = i / 8;
                    int jj = j / 8;

                    retVal[ii * 8 + jj]++;
                }
            }
        }

        // skaliranje sa [0,64] na [-1,1]
        for (int i = 0; i < retVal.length; i++)
        {
            retVal[i] = retVal[i] / 32 - 1;
        }
        return retVal;
    }
    
    private String Prepoznaj(BufferedImage bmp)
    {
        String prepoznato = "";

        short[][] slika = ToolbarStandard.kMeansRecognition(bmp);

        ArrayList<RasterRegion> regions = ImageUtil.regionLabeling(slika);
        for (RasterRegion reg : regions)
        {
            reg.odrediMomente();
        }
        
        regions = SpojiTackeIKukice(regions);

        for (RasterRegion reg : regions)
        {
            reg.odrediMomente();
        }


        ArrayList<ArrayList<RasterRegion>> rows = new ArrayList<ArrayList<RasterRegion>>();
        ArrayList<RasterRegion> pom = new ArrayList<RasterRegion>();

        for (int i = 0; i < regions.size() - 1; i++)
        {
            double max = Math.max(0.9*Math.max(regions.get(i).maxY - regions.get(i).minY, regions.get(i+1).maxY - regions.get(i+1).minY), 15);
            if (Math.abs(regions.get(i).yM - regions.get(i+1).yM) < max) //&& regions[i].maxX < regions[i + 1].minX)//Math.Abs(regions[i].maxX - regions[i + 1].minX)< 100*Math.Abs(regions[i].minX - regions[i].maxX))
            {
                pom.add(regions.get(i));
                if (i == regions.size() - 2)
                    pom.add(regions.get(i+1));
            }
            else
            {
                pom.add(regions.get(i));
                ArrayList<RasterRegion> pom1 = new ArrayList<RasterRegion>();
                pom1.addAll(pom);
                rows.add(pom1);
                pom.clear();
                if (i == regions.size() - 2)
                    pom.add(regions.get(i+1));
            }
        }
        if (pom.size() > 0)
            rows.add(pom);
       
        ArrayList<Double> paragraph = new ArrayList<Double>();
        KMeans1 km1 = new KMeans1();
        
       for ( int k = 0; k < rows.size()-1; k++)
        {
            if (rows.get(k).size() == 0) continue;
            paragraph.add((double)Math.abs(rows.get(k).get(0).minY - rows.get(k+1).get(0).maxY));
        }
        
       double minC1 = 0;
       double maxC1 = 0;
       
        km1.elementi = paragraph;
        if (km1.elementi.size() != 0) {
        km1.podeliUGRupe(2, 1);
         minC1 = Math.min(km1.grupe.get(0).centar, km1.grupe.get(1).centar);
         maxC1 = Math.max(km1.grupe.get(0).centar, km1.grupe.get(1).centar);
        }
        for ( int k = 0; k < rows.size(); k++)
        {
        	ArrayList<RasterRegion> regions1 = rows.get(k);
            ArrayList<Double> razmak = new ArrayList<Double>();
        	Collections.sort(regions1);
            for (int i = 0; i < regions1.size() - 1; i++)
            {
                razmak.add((double) Math.abs(regions1.get(i).maxX - regions1.get(i+1).minX));
            }
        	equalizeRegions1(regions1);
            if (regions1.size() == 0) continue;

        	           
            KMeans1 km = new KMeans1();
           km.elementi = razmak;
            if (km.elementi.size() != 0) 
            km.podeliUGRupe(2, 1);
            double minC = Math.min(km.grupe.get(0).centar, km.grupe.get(1).centar);
            double maxC = Math.max(km.grupe.get(0).centar, km.grupe.get(1).centar);
            for (int i = 0; i < regions1.size(); i++)
            {
                RasterRegion reg = regions1.get(i);
                reg.odrediMomente();
                short[][] regSlika = reg.odrediNSliku();
                regSlika = ImageUtil.resizeImage(regSlika, new Dimension(64, 64));
                double[] ulaz = pripremiSlikuZaVNM(regSlika);
                int cifra = bp.izracunajIndeks(ulaz);
                prepoznato += alfabetInv.get(cifra);
                    if (maxC-minC > 0.2*(reg.maxY - reg.minY))
                    if (i != regions1.size() - 1)
                        if (Math.abs(minC - razmak.get(i)) > Math.abs(maxC - razmak.get(i)))
                            prepoznato += " ";
             
            }
            if (maxC1-minC1 > (regions1.get(0).maxY - regions1.get(0).minY))
                if (k != rows.size() - 1)
                    if (Math.abs(minC1 - paragraph.get(k)) > Math.abs(maxC1 - paragraph.get(k)))
                        prepoznato += newLine;
           prepoznato += newLine;
        }

          String levPrepoznato = "";
        String pomocni = prepoznato.substring(0, prepoznato.length()-2);
         //string[] recenice = prepoznato.Split('\n')
        String[] recenice = pomocni.split("\r\n");
         for (String recenica : recenice)
         {
        	 System.out.println(recenica+"+");
         	String[] reci = recenica.split(" ");
             for (String rec : reci)
             {
            	 if(rec==newLine || rec=="")
            		 break;
             	String minRec = "";
                 int minRastojanje = 3;
                 if(isAlfanum(rec)){
                 if (recnik.contains(rec.toLowerCase()))
                     minRec = rec;
                 else for (String value : (HashSet<String>) recnik)  // I'm sure this cast will throw as well
                     {
                         int rastojanje = Levenshtein.Levenshtein.LevenshteinDistance(value.toLowerCase().trim(), rec.toLowerCase().trim());
                         if (rastojanje < minRastojanje)
                         {
                             minRastojanje = rastojanje;
                             minRec = value;
                             
                             if (minRastojanje == 0)
                                 break;
                         }
                     }
                 if(minRec=="")
                	 minRec=rec;
                 levPrepoznato += minRec + " ";
                 }
                 else{
                	 int n;
                	 n = rec.length()-1;
                	 
                 	 String s = "'";
                	 if(rec.charAt(n)==s.charAt(0)){
                		 String recn = rec.substring(0, n); 
                		 recn+=",";
                		 rec=recn;
                		String recp = rec.replace('!', 'l');
                		rec=recp;
                	 }
                	 if((rec.charAt(0)==s.charAt(0) && rec.charAt(1)==s.charAt(0)) ||
                			 (rec.charAt(0)=='.' && rec.charAt(1)==s.charAt(0)) ||
                					 (rec.charAt(0)==s.charAt(0) && rec.charAt(1)=='.') ||
                					 (rec.charAt(0)==',' && rec.charAt(1)==s.charAt(0)) ||
                					 (rec.charAt(0)==s.charAt(0) && rec.charAt(1)==',')){
                		 String recn = rec.substring(2);
                		 rec='"'+recn;
                	 }
                	 if((rec.charAt(rec.length()-1)==s.charAt(0) && rec.charAt(rec.length()-2)==s.charAt(0)) ||
                			 (rec.charAt(rec.length()-1)=='.' && rec.charAt(rec.length()-2)==s.charAt(0)) ||
                					 (rec.charAt(rec.length()-1)==s.charAt(0) && rec.charAt(rec.length()-2)=='.') ||
                					 (rec.charAt(rec.length()-1)==',' && rec.charAt(rec.length()-2)==s.charAt(0)) ||
                					 (rec.charAt(rec.length()-1)==s.charAt(0) && rec.charAt(rec.length()-2)==',')){
                		 String recn = rec.substring(0,rec.length()-2);
                		 
                		 recn+='"';
                		 rec=recn;
                	 }
                	 if(rec.charAt(rec.length()-1)=='!'){
                		 String recp = rec.substring(0,rec.length()-1);
                		 String rech = recp.replace('!', 'l');
                		 rec = rech+"!";
                	 }
                	 else{
                		 String recp = rec.replace('!', 'l');
                  		rec=recp;
                	 }
                	 
                		 
                	 levPrepoznato += rec + " ";
                 }
             }
             levPrepoznato = levPrepoznato.trim();
            
             levPrepoznato += newLine;
         }
         return levPrepoznato.substring(0, levPrepoznato.length() - 2);
      //  return prepoznato;
    }
    
    public boolean isAlfanum(String rec){
    	for(int i=0; i<rec.length();i++){
    		if(!Character.isLetter(rec.charAt(i)) || rec.charAt(i)=='č' || rec.charAt(i)=='ć' || 
    				rec.charAt(i)=='ž'){
    			return false;
    		}
    	}
    	return true;
    }
	public VerticalToolbar() {
		
		//super(SwingConstants.VERTICAL);
		setPreferredSize(new Dimension(300,250));
	
		kandidati = new ArrayList<RasterRegion>();
		FileInputStream fstream = null;
		recnik = new HashSet<String>();
		try {
			fstream = new FileInputStream("sr-Latn.dic");
			BufferedReader br = new BufferedReader(new InputStreamReader(fstream));

			String strLine;

			while ((strLine = br.readLine()) != null)   {
			  // Print the content on the console
			  recnik.add(strLine);
			}

			br.close();
		} catch (FileNotFoundException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		
		
		String big  = "ABCČĆDĐEFGHIJKLMNOPRSŠTUVZŽ";

		String small  = "abcčćdđefghijklmnoprsštuvzž";
		
		String chars = "!\'\'#$%&/()=?*|+_]}[{;:\',<.>~`@-";
		
		String num  = "0123456789";
		
		jtxt1 = new JTextArea();
		jtxt1.setPreferredSize(new Dimension(220,250));
	/*	String result = big + newLine + small + newLine + big + newLine + small + newLine + big + newLine + small + newLine
				+ big + newLine + small + newLine + big + newLine + small + newLine + chars + newLine + num;
		*/
		String result = big + small + chars + num;
		jtxt1.setText(result);
        System.out.println(result.replace("\n", "").replace("\r", "").length());
		bt1 = new JButton("Obelezi Kandidate");
		
		bt1.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
		            short[][] oSlika = ImageUtil.bitmapToByteMatrix(ToolbarStandard.img);
		            short[][] slika = ImageUtil.matrixToBinary(oSlika, 200);
		             
		            
		             ArrayList<RasterRegion> kandidati1 = ImageUtil.regionLabeling(slika);
		             
		             System.out.println("regioni: " + kandidati1.size());
		             
		             for (RasterRegion reg : kandidati1)
		             {
		                 if (reg.points.size() > 1)
		                     kandidati.add(reg);
		             }

		            for (RasterRegion reg : kandidati)
		            {
		                reg.odrediMomente();
		            }

		            System.out.println("regioni: " + kandidati.size());
		            
		            // ovde spojiti tacke i kukice njima odgovarajucim slovima
		            kandidati = SpojiTackeIKukice(kandidati);

		            for (RasterRegion reg : kandidati)
		            {
		                reg.odrediMomente();
		            }		            
		            
		            System.out.println("regioni: " + kandidati.size());

		            // ovde sloziti slova u redove i kolone
		            String[] linije = jtxt1.getText().replace("\r", "").split("\\n");
		            String slova = jtxt1.getText().replace("\n", "").replace("\r", "");

		            int rr = 0;
		            ArrayList<RasterRegion> slozeniKandidati = new ArrayList<RasterRegion>();
		            for (int i = 0; i < linije.length; i++)
		            {
		                String linija = linije[i];
		                int N = linija.length();
		                ArrayList<RasterRegion> red = new ArrayList<RasterRegion>();
		                for (int j = 0; j < N; j++)
		                {
		                    red.add(kandidati.get(rr));
		                    rr++;
		                }
		                equalizeRegions(red);
		                Collections.sort(red);
		                for (RasterRegion regS : red)
		                    slozeniKandidati.add(regS);
		            }
		            kandidati = slozeniKandidati;
		            
		            int regId = 0;
		            int redBr = 0;
		            for (RasterRegion reg : kandidati)
		            {
		            	
		                reg.Tag = "" + String.valueOf(slova.charAt(regId));
		                if (!alfabet.containsKey(reg.Tag))
		                {
		                    alfabet.put(reg.Tag, redBr);
		                    alfabetInv.put(redBr, reg.Tag);
		                    redBr++;
		                }
		                regId++;
		            }
		           
			}
		});
		add(bt1);
		
		JScrollPane scroll1 = new JScrollPane (jtxt1, 
				   JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
		
		
		add(scroll1);

		
		bt2 = new JButton("Formiraj Obucavajuci Skup");
		
		
		bt2.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				
				brojUzoraka = kandidati.size();
	            obucavajuciSkup = new double[brojUzoraka][2][100];
	            Dimension size = new Dimension(64, 64);
	            for (int uzorak = 0; uzorak < brojUzoraka; uzorak++)
	            {
	                RasterRegion reg = kandidati.get(uzorak);

	                short[][] regSlika = reg.odrediNSliku(); // ispravi region da stoji uspravno
	                short[][] nSlika = ImageUtil.resizeImage(regSlika, size); // resize na 64x64
	                double[] ulaz = pripremiSlikuZaVNM(nSlika); // kreiraj vektor od 64 elementa na osnovu 64x64 slike
	                int index = alfabet.get(reg.Tag); // nadji koji je index (u izlaznom sloju) obelezeni region

	                // formiranje obucavajuceg skupa
	                // - na ulaze neuronske mreze dovodi se kreirani vektor od 64 elementa
	                for (int k = 0; k < ulaz.length; k++)
	                {
	                    obucavajuciSkup[uzorak][0][k] = ulaz[k];
	                }

	                // - na izlaz koji odgovara indeksu postaviti 1, na ostale 0
	                for (int ii = 0; ii < alfabet.size(); ii++)
	                {
	                    if (ii == index)
	                        obucavajuciSkup[uzorak][1][ii] = 1;
	                    else
	                        obucavajuciSkup[uzorak][1][ii] = 0;
	                }
	            }
	            JOptionPane.showMessageDialog(null, "Obucavajuci skup formiran!");
				
			}
		});
		add(bt2);
		
		bt3 = new JButton("Obucavanje");
		
		
		bt3.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				
				 if (bp != null)
		            {
		                brojUzoraka = obucavajuciSkup.length + bp.obucavajuciSkup.length;
		                double[][][] novi = new double[brojUzoraka][2][100];
		                for (int i = 0; i < brojUzoraka; i++)
		                {
		                    if (i < obucavajuciSkup.length)
		                    {
		                        for (int j = 0; j < obucavajuciSkup[0].length; j++)
		                        {
		                            for (int k = 0; k < obucavajuciSkup[0][0].length; k++)
		                            {
		                                novi[i][j][k] = obucavajuciSkup[i][j][k];
		                            }
		                        }
		                    }
		                    else
		                    {
		                        for (int j = 0; j < bp.obucavajuciSkup[0].length; j++)
		                        {
		                            for (int k = 0; k < bp.obucavajuciSkup[0][0].length; k++)
		                            {
		                                novi[i][j][k] = bp.obucavajuciSkup[i - obucavajuciSkup.length][j][ k];
		                            }
		                        }
		                    }
		                }

		                obucavajuciSkup = novi;
		            }
		            bp = new BackPropagation(obucavajuciSkup);
		            bp.obuci();
		            JOptionPane.showMessageDialog(null, "Obucen!");
			}
		});
		add(bt3);
		
		bt4 = new JButton("Prepoznavanje");
		
		
		bt4.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				 String prepoznato = Prepoznaj(ToolbarStandard.img);
		         jtxt2.setText(prepoznato);			
		    //     MainFrame.getInstance().repaint();
				
			}
		});
		add(bt4);
		add(Box.createRigidArea(new Dimension(15, 80)));
		jtxt2 = new JTextArea();
		jtxt2.setPreferredSize(new Dimension(220,250));
		JScrollPane scroll2 = new JScrollPane (jtxt2, 
				   JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
		add(scroll2);
	}
	

}
